#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "../../include/list.h"
#include "../../include/hash_tbl.h"

#define BUCKETS	11

static int match_char(const void *char1, const void *char2)
{
	return (*(const char *)char1 == *(const char *)char2);
}

static int hash_char(const void *key)
{
	return *(const char *)key % BUCKETS;
}

static void print_table(const ch_hash_tbl_t *tbl)
{
	int idx;
	list_node_t *n;

	fprintf(stdout, "table size is %d\n", ch_hash_tbl_size(tbl));

	for (idx = 0; idx < tbl->buckets; idx++)
	{
		fprintf(stdout, "bucket[%d] = ", idx);
		for (n = list_head(&tbl->table[idx]); n != NULL; n = list_next(n))
			fprintf(stdout, "%c", *(char *)list_data(n));

		fprintf(stdout, "\n");
	}

	return;
}


int main(int argc, char *argv[])
{
	ch_hash_tbl_t tbl;
	unsigned int idx;
	char *data, c;
	int ret;

	if (ch_hash_tbl_init(&tbl, BUCKETS, hash_char, match_char, free))
		return 1;

	for (idx = 0; idx < BUCKETS; idx++)
	{
		if (!(data = (char *)malloc(sizeof(char))))
			return 1;

		*data = (idx * 6 + 5) % 23 + 'A';

		if (ch_hash_tbl_insert(&tbl, (const void **)data))
			return 1;

		print_table(&tbl);
	}

	for (idx = 0; idx < BUCKETS; idx++)
	{
		if (!(data = (char *)malloc(sizeof(char))))
			return 1;

		*data = (idx * 4 + 3) % 23 + 'a';
		if (ch_hash_tbl_insert(&tbl, (const void **)data))
			return 1;
		print_table(&tbl);
	}

	if (!(data = (char *)malloc(sizeof(char))))
		return 1;
	*data = 'd';
	ret = ch_hash_tbl_insert(&tbl, (const void **)data);
	if (!ret)
		free(data);
	fprintf(stdout, "inserting d again, ret = %d\n", ret);

	fprintf(stdout, "removing d G S\n");
	c = 'd';
	data = &c;
	if (!ch_hash_tbl_remove(&tbl, (void **)&data))
		free(data);


	c = 'G';
	data = &c;
	if (!ch_hash_tbl_remove(&tbl, (void **)&data))
		free(data);

	c = 'S';
	data = &c;
	if (!ch_hash_tbl_remove(&tbl, (void **)&data))
		free(data);

	print_table(&tbl);

	if (!(data = (char *)malloc(sizeof(char))))
		return 1;
	*data = 'd';
	ret = ch_hash_tbl_insert(&tbl, (const void **)data);
	if (!ret)
		free(data);
	fprintf(stdout, "inserting d again2, ret = %d\n", ret);

	if ((data = (char *)malloc(sizeof(char))) == NULL)
   		return 1;

	*data = 'G';

	if (!(ret = ch_hash_tbl_insert(&tbl, (const void **)data)))
	   free(data);

	fprintf(stdout, "Trying to insert G again...Value=%d (0=OK)\n", ret);
	print_table(&tbl);

	fprintf(stdout, "Inserting X and Y\n");
	if (!(data = (char *)malloc(sizeof(char))))
	   return 1;
	*data = 'X';
	if (ch_hash_tbl_insert(&tbl, (const void **)data))
	   return 1;

	if (!(data = (char *)malloc(sizeof(char))))
	   return 1;
	*data = 'Y';
	if (ch_hash_tbl_insert(&tbl, (const void **)data))
	   return 1;
	   
	print_table(&tbl);

	ch_hash_tbl_destroy(&tbl);

	return 0;
}

